package org.artifact.core.plugin.csv;

import java.io.File;
import java.io.FileFilter;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.WatchEvent;
import java.util.List;
import java.util.function.BiConsumer;

import org.artifact.core.db.BaseCsv;
import org.artifact.core.lang.IPlugin;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.watch.WatchMonitor;
import cn.hutool.core.io.watch.Watcher;
import cn.hutool.core.text.csv.CsvData;
import cn.hutool.core.text.csv.CsvReadConfig;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.hutool.setting.Setting;

public class CsvPlugin implements IPlugin {
	
	static final Log log = LogFactory.get(CsvPlugin.class);
	
	/** 下载路径 */
	private String downloadUrl;
	/** 校验文件名 */
	private String verifyFileName;
	/** CSV文件夹 */
	private String csvFolderPath;
	/** 提供器的包 */
	private String providerPackage;
	/** 监控 */
	private boolean monitor;
	
	
	private WatchMonitor watchMonitor;
	private CsvReader reader;
	private BiConsumer<Class<BaseCsv>, CsvData> consumer;
	
	public CsvPlugin(String downloadUrl, String verifyFileName, String csvFolderPath,String providerPackage, boolean monitor,BiConsumer<Class<BaseCsv>, CsvData> consumer) {
		super();
		this.downloadUrl = downloadUrl;
		this.verifyFileName = verifyFileName;
		this.csvFolderPath = csvFolderPath;
		this.providerPackage = providerPackage;
		this.monitor = monitor;
		this.consumer = consumer;
		CsvReadConfig config = new CsvReadConfig();
    	config.setFieldSeparator(';');
    	reader = new CsvReader(config);
	}

	@Override
	public boolean start() {
		
		try {
			// 1.下载
			if (StrUtil.isNotBlank(downloadUrl)) {
				download();
			}
			
			
	    	// 2.加载
			List<File> files =FileUtil.loopFiles(csvFolderPath, new FileFilter() {
				@Override
				public boolean accept(File pathname) {
					return StrUtil.endWith(pathname.getName(), ".csv");
				}
			});
			
			for (File file : files) {
				Class<BaseCsv> clazz = getClassByFileName(file.getName());
				consumer.accept(clazz, reader.read(file));
			}
			
			// 3.监控
			if (monitor) {
				monitor();
			}
			return true;
		} catch (Exception e) {
			log.error(e);
		}
		return false;
	}

	private Class<BaseCsv> getClassByFileName(String fileName) {
		fileName =  StrUtil.removeSuffix(fileName, ".csv");
		// 2.转驼峰
		fileName = StrUtil.toCamelCase(fileName);
		// 3. 首字母大写
		fileName = StrUtil.upperFirst(fileName);
		
		Class<BaseCsv> clazz = ClassUtil.loadClass(providerPackage + "." + fileName);
		
		return clazz;
	}

	private void monitor() {
		watchMonitor = WatchMonitor.create(csvFolderPath, WatchMonitor.ENTRY_MODIFY);
		
		watchMonitor.setWatcher(new Watcher(){

    	    @Override
    	    public void onModify(WatchEvent<?> event, Path currentPath) {
    	    	String fileName = event.context().toString();
    	    	Class<BaseCsv> clazz = getClassByFileName(fileName);
    	    	if (clazz != null) {
    	    		File file = FileUtil.newFile(csvFolderPath + File.separator + fileName);
    	    		consumer.accept(clazz, reader.read(file));
				}
    	    	log.info("修改：{}-> {}", currentPath, fileName);
    	    }

			@Override
			public void onCreate(WatchEvent<?> event, Path currentPath) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void onDelete(WatchEvent<?> event, Path currentPath) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void onOverflow(WatchEvent<?> event, Path currentPath) {
				// TODO Auto-generated method stub
				
			}
    	});

    	//设置监听目录的最大深入，目录层级大于制定层级的变更将不被监听，默认只监听当前层级目录
    	watchMonitor.setMaxDepth(3);
    	//启动监听
    	watchMonitor.start();
	}



	private void download() {
		// 下载校验文件
		long contentSize = HttpUtil.downloadFile(downloadUrl + verifyFileName, csvFolderPath);
		if (contentSize > 0) {
			Setting setting = new Setting(new File(csvFolderPath + verifyFileName),Charset.forName("UTF-8"),false);
			setting.forEach((k,v) -> {
				String fielName = k.toString();
				if(FileUtil.exist(csvFolderPath + fielName)){
					String content = FileUtil.readString(csvFolderPath + fielName, "UTF-8");	
					String md5 = SecureUtil.md5(content);
					// 文件没有变动
					if (v.equals(md5)) {
						return;
					}
				}
				HttpUtil.downloadFile(downloadUrl + fielName, csvFolderPath);
			});
		}
	}

	@Override
	public boolean stop() {
		if (monitor && watchMonitor!=null) {
			watchMonitor.stop();
		}
		return true;
	}

}
